﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Windows;
using VMDS.Business.Entities;
using VMDS.Business.Processes;
using VMDS.GUIClient.ServiceReference;
using VMDS.GUIClient.ViewModels;
using VMDS.Settings;

namespace VMDS.GUIClient.Model
{
    class FileCompare : System.Collections.Generic.IEqualityComparer<System.IO.FileInfo>
    {
        public FileCompare() { }

        public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2)
        {
            return (f1.Name == f2.Name &&
                    f1.Length == f2.Length);
        }

        // Return a hash that reflects the comparison criteria. According to the 
        // rules for IEqualityComparer<T>, if Equals is true, then the hash codes must
        // also be equal. Because equality as defined here is a simple value equality, not
        // reference identity, it is possible that two or more objects will produce the same
        // hash code.
        public int GetHashCode(System.IO.FileInfo fi)
        {
            string s = String.Format("{0}{1}", fi.Name, fi.Length);
            return s.GetHashCode();
        }
    }


    static class Checker
    {
        static bool CheckDuplicate()
        {
            bool result = true ;
            if (SysInfo.Already_Started("VMDS_CLIENT"))
            {
                WindowFinder.ShowFromTray("Клиент VMDS");
                result = false;
            }
            return result;
        }

        static bool CheckLocalConnect()
        {
            bool result;
            try
            {
                ClientServiceContractClient client = ServiceLocator.ClientService;
                client.Open();
                result = true;
                client.Close();
            }
            catch
            {
                result = false;
            }
            return result;
        }

        static void Exit()
        {
            MessageListener.Instance.ChangeProgress(0);
            Thread.Sleep(2000);
            Environment.Exit(0); 
        }
        static void Rollback()
        {
            for (int i = MessageListener.Instance.Progress; i >0; i--)
            {
                MessageListener.Instance.ChangeProgress(i);
                Thread.Sleep(100);
            }
        }

        private static BackgroundWorker screenloader;
        public static void LoadData()
        {
            try
            {
                ServiceLocator.MainService.TestRights();
                Repozitory.AdmAvailable = true;
            }
            catch
            {
                Repozitory.AdmAvailable = false;
            }


            try
            {
                Repozitory.OnlineVms = new List<VM>(ServiceLocator.MainService.GetVMs());
                screenloader=new BackgroundWorker();
                screenloader.DoWork += new DoWorkEventHandler(screenloader_DoWork);
                screenloader.RunWorkerAsync();

            }
            catch (Exception ex)
            {
                Repozitory.AdmAvailable = false;
                var msg = ex.Message;
            }
            Repozitory.OfflineVms = ServiceLocator.ClientService.GetOfflineVMs();
            
        }

        static bool CompareDir(string pathA,string pathB,string pattern)
        {
            

            System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA);
            System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB);

            // Take a snapshot of the file system.
            IEnumerable<System.IO.FileInfo> list1 = dir1.GetFiles(pattern, System.IO.SearchOption.AllDirectories);
            IEnumerable<System.IO.FileInfo> list2 = dir2.GetFiles(pattern, System.IO.SearchOption.AllDirectories);

            //A custom file comparer defined below
            FileCompare myFileCompare = new FileCompare();

            // This query determines whether the two folders contain
            // identical file lists, based on the custom file comparer
            // that is defined in the FileCompare class.
            // The query executes immediately because it returns a bool.
            bool areIdentical = list1.SequenceEqual(list2, myFileCompare);
            return areIdentical;
        }

        static void SyncDir(string from,string to,string pattern)
        {
            foreach (var file in Directory.EnumerateFiles(to,pattern))
            {
                try
                {
                    File.Delete(file);
                }
                catch { }
            }
            foreach (var file in Directory.EnumerateFiles(from,pattern))
            {
                var fn = new FileInfo(file).Name;
                File.Copy(file,to+"\\"+fn,true);
            }
        }

        static void screenloader_DoWork(object sender, DoWorkEventArgs e)
        {
            ClientConfiguration cfg = new ClientConfiguration("d:\\virtual\\data\\config.ini");
            List<string> sp = new List<string>() { "*.jpg", "*.gif", "*.png", "*.bmp" };
            var share = ServiceLocator.MainService.GetShareUNC();
            var cache = cfg.LocalStorage+"cache\\screenshots";
            foreach (var vm in Repozitory.OnlineVms)
            {
                var pathA = cache + "\\" + vm.Name;
                var pathB = share + "\\vm\\" + vm.Name;
                if (!Directory.Exists(pathA)) Directory.CreateDirectory(pathA);
                foreach (var pat in sp)
                {
                    if (!CompareDir(pathA,pathB,pat)) SyncDir(pathB,pathA,pat);
                }
            }
        }


        public static bool FindAndKillProcess(string name)
        {
            var p = Process.GetProcesses();
            foreach (Process clsProcess in p)
            {
                if (clsProcess.ProcessName.ToLower() == name.ToLower())
                {
                    clsProcess.Kill();
                    return true;
                }
            }
            return false;
        } 


        public static void LoadCheck()
        {
            MessageListener message = MessageListener.Instance;

            FindAndKillProcess("Vmds");
            message.ReceiveMessage("Поиск запущенного клиента");
            message.ChangeProgress(10);
            if (!CheckDuplicate())
            {
                message.ReceiveMessage("Клиент уже запущен. Завершение работы");
                Rollback();
                Exit();
            }
          
            message.ChangeProgress(20);
            message.ReceiveMessage("Подключение к службе");
            if (!CheckLocalConnect())
            {
                message.ReceiveMessage("Ошибка: Не удалось подключиться к службе");
                Rollback();
                Exit();
            }

            if (!Directory.Exists("d:\\"))
            {
                message.ReceiveMessage("Ошибка: диск d: отсутствует");
                Rollback();
                Exit();
            }
            var gb = new DriveInfo("d").AvailableFreeSpace/(1024*1024*1024);
            if (gb < 2)
            {
                MessageBox.Show("На диске d: осталось мало свободного места");
            }
            message.ReceiveMessage("Поиск обновлений");
            if (ServiceLocator.ClientService.CheckUpdate())
            {
                try
                {
                    Process.Start("d:\\virtual\\vmds.exe", "update");
                }
                catch { }
                ServiceLocator.ClientService.Update();
                message.ReceiveMessage("Обновление");
                Environment.Exit(0);

            }
            var vmp = new SoftWare() {Productname = "VMware Player"};
            vmp.Update();
            if (!vmp.Installed)
            {
                message.ReceiveMessage("VMware Player не обнаружен");
            }
            Repozitory.VMplayerPath = vmp.InstallPath;
                message.ChangeProgress(30);
           
            message.ChangeProgress(40);
            message.ReceiveMessage("Загрузка данных");
            try
            {
                LoadData();
            }
            catch
            {
                message.ReceiveMessage("Ошибка получения данных");
                Rollback();
                Exit();
            }

            message.ReceiveMessage("Создание окон");
            message.ChangeProgress(100);
        }
        
    }
}
